﻿
#ifndef ___________LCH_PBR__________
#define  ___________LCH_PBR__________


 
struct LchSurfaceData
{
    half3 albedo;
 
    half  metallic;
    half  smoothness;
    half3 normalTS;
    half3 emission;
    half  occlusion;
    half  alpha;


    #ifdef _SSS
    half4 sssColor;
 
    half sssAmb;
    #endif

 
   
    half3 anisoGlass;
    half primaryShift;
 
    half anisoPower;

    half maxLimit;

    half3 anisoDirTS;
     
    half backLight;
};

struct LchAnisoData
{
    half3 anisoGlass;
    half primaryShift;
 
    half anisoPower;
    half3 anisoDirWS;
    half smoothness;
};

 


#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/BRDF.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ImageBasedLighting.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl"
 

void InitAnisoData( LchSurfaceData surfaceData, out  LchAnisoData data,InputData inputData)
{
     #if defined( ANISOTROPIC_ON )||defined(  ANISOTROPIC_FLOWMAP)

    data.anisoGlass = surfaceData.anisoGlass;

    data.smoothness  = surfaceData.smoothness;
    data.primaryShift = surfaceData.primaryShift;
 
    data.anisoPower = surfaceData.anisoPower;
 
    data.anisoDirWS =  TransformTangentToWorld(surfaceData.anisoDirTS, inputData.tangentToWorld);;
    
    #else
    data.anisoGlass = 0.0;
    data.primaryShift = 0.0;
  
    data.anisoPower = 0.0;
    data.smoothness = 0.0;
    data.anisoDirWS = float3(1.0,0.0,0.0);
    #endif
}


inline void InitializeBRDFData(LchSurfaceData surfaceData,  out BRDFData outBRDFData)
{

 

     half3 albedo = surfaceData.albedo;
 
    half oneMinusReflectivity = OneMinusReflectivityMetallic(surfaceData.metallic);
    half reflectivity = 1.0 - oneMinusReflectivity;
    half3 brdfDiffuse = albedo * oneMinusReflectivity;
    half3 brdfSpecular = lerp(kDieletricSpec.rgb, albedo, surfaceData.metallic);
 

    InitializeBRDFDataDirect(albedo, brdfDiffuse, brdfSpecular, reflectivity, oneMinusReflectivity, surfaceData.smoothness,  surfaceData.alpha, outBRDFData);
 
   


    
}

 
#ifdef _CUSTOM_SKYBOX
SAMPLER(sampler_CustomCubeTex);
TEXTURECUBE(_CustomCubeTex);
//这个加入到需要地方的声明
//float4 _CustomCubeTex_HDR;
#endif
#ifdef SCREEN_SPACE_REF
static float2 refScreenPos = float2(0,0);
static float refBlendValue = 0;
void SetRefScreenPos(float3 refPosWS)
{
    float4 positionHCS0 = TransformWorldToHClip(refPosWS);
	float4 screenPosition0 = ComputeScreenPos(positionHCS0);
	refScreenPos =	   screenPosition0.xy / screenPosition0.w;

    float2 t1 = abs(refScreenPos.xy-0.5);
    float t = max(t1.x,t1.y);
    t = saturate((0.5 - t) / 0.1 );
    refBlendValue = t;

}
half3 blendSreen(float3 refCol)
{
   
    return  lerp( refCol,SAMPLE_TEXTURE2D(_CameraOpaqueTexture, sampler_CameraOpaqueTexture, refScreenPos).xyz ,refBlendValue);
}
#endif
half3 GlossyEnvironmentReflectionEX(half3 reflectVector, half perceptualRoughness, half occlusion)
{

    
#ifdef _CUSTOM_SKYBOX
    half3 irradiance;
     half mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness);
     half4 encodedIrradiance =  SAMPLE_TEXTURECUBE_LOD(_CustomCubeTex, sampler_CustomCubeTex, reflectVector, mip);

     #if defined(UNITY_USE_NATIVE_HDR)
        irradiance = encodedIrradiance.rgb;
    #else
        irradiance = DecodeHDREnvironment(encodedIrradiance, _CustomCubeTex_HDR);
    #endif // UNITY_USE_NATIVE_HDR

    #ifdef SCREEN_SPACE_REF
    irradiance = blendSreen(irradiance);
    #endif
        return irradiance * occlusion*_CustomCubeTexBrightness;
    
#else


#if !defined(_ENVIRONMENTREFLECTIONS_OFF)
    half3 irradiance;
    half mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness);
    half4 encodedIrradiance = half4(SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectVector, mip));

    #if defined(UNITY_USE_NATIVE_HDR)
        irradiance = encodedIrradiance.rgb;
    #else
        irradiance = DecodeHDREnvironment(encodedIrradiance, unity_SpecCube0_HDR);

    #endif // UNITY_USE_NATIVE_HDR
          

          #ifdef SCREEN_SPACE_REF
            irradiance = blendSreen(irradiance);
          #endif
        #if defined(CUSTOM_CUBEMAP_BRIGHTNESS)
         
         return irradiance * occlusion *_CustomCubeTexBrightness;
        #else
          return irradiance * occlusion;
    #endif // UNITY_USE_NATIVE_HDR
       
    #else

         #if defined(CUSTOM_CUBEMAP_BRIGHTNESS)
 
            return _GlossyEnvironmentColor.rgb * occlusion *_CustomCubeTexBrightness ;
        #else

             return _GlossyEnvironmentColor.rgb * occlusion ;
        #endif
     
       
    #endif // _ENVIRONMENTREFLECTIONS_OFF

#endif
}


// Computes the specular term for EnvironmentBRDF
half3 LchEnvironmentBRDFSpecular(BRDFData brdfData, half fresnelTerm)
{
     
    
    #ifdef NO_FRESNEL_TERM
    float surfaceReduction = 1.0 / (brdfData.roughness2 + 1.0);
    return half3(surfaceReduction * brdfData.specular);
    #else
    float surfaceReduction = 1.0 / (brdfData.roughness2 + 1.0);
    return half3(surfaceReduction * lerp(brdfData.specular, brdfData.grazingTerm, fresnelTerm));
    #endif
    
}

half3 LchEnvironmentBRDF(BRDFData brdfData, half3 indirectDiffuse, half3 indirectSpecular, half fresnelTerm)
{
    half3 c = indirectDiffuse * brdfData.diffuse;
    c += indirectSpecular * LchEnvironmentBRDFSpecular(brdfData, fresnelTerm);
    return c;
}
half3 LchGlobalIllumination(BRDFData brdfData,  
    half3 bakedGI, half occlusion,
    half3 normalWS, half3 viewDirectionWS)
{
    half3 reflectVector = reflect(-viewDirectionWS, normalWS);
    half NoV = saturate(dot(normalWS, viewDirectionWS));
    half fresnelTerm = Pow4(1.0 - NoV);

    half3 indirectDiffuse = bakedGI;
    half3 indirectSpecular = GlossyEnvironmentReflectionEX(reflectVector, brdfData.perceptualRoughness, half(1.0));
    #ifdef SCREEN_SPACE_REF
    return indirectSpecular;

    #endif
    half3 color = LchEnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm);

     
    return color * occlusion;
 
}


half LchNDFAnisotropicNormalizedTerm(half3 T, half3 H, half exponent)
{
	half dotTH = dot(T, H);
	half sinTH = sqrt(1 - dotTH * dotTH);
	half dirAtten = smoothstep(-1, 0, dotTH);
	return dirAtten * pow(sinTH, exponent);
} 
 
 
 half3 LchShiftTangent(half3 T, half3 N, half shift)
{
	return normalize(T + shift * N);
}
inline half LchRoughnessToSpecPower(half m)
{
	half sq = max(1e-4f, m*m);
	half n = (2.0 / sq) - 2.0;                          // https://dl.dropboxusercontent.com/u/55891920/papers/mm_brdf.pdf
	n = max(n, 1e-4f);                                  // prevent possible cases of pow(0,0), which could happen when roughness is 1.0 and NdotH is zero
	return n;
}
half BlinnPhongNormTerm(half n)
{
	return  (n + 2.0) * (0.1589356903284295);
}
#define HALF_MIN 6.103515625e-5  // 2^-14, the same value for 10, 11 and 16-bit: https://www.khronos.org/opengl/wiki/Small_Float_Formats

half3 LchDirectBRDFSpecular(BRDFData brdfData,
      LchAnisoData anisoData,
      half3 normalWS,
   
      half3  anisoDirWS,
     
    half3 lightDirectionWS, half3 viewDirectionWS)
{
   
 
    float3 halfDir = SafeNormalize(lightDirectionWS + float3(viewDirectionWS));

    


    #if defined(ANISOTROPIC_ON) || defined(ANISOTROPIC_FLOWMAP) 

 
   float LDotH = max(dot(lightDirectionWS, halfDir), HALF_MIN);
	//float nDotH = max(dot(worldNormal, halfVector), HALF_MIN);
   half3 anisoWS = normalize(anisoDirWS);
  
	//half specPower = LchRoughnessToSpecPower(brdfData.roughness);
    //* BlinnPhongNormTerm(specPower)
	half3 t1 = ShiftTangent(anisoWS, normalWS, anisoData.primaryShift);
 
 
 
	float3 D =  LchNDFAnisotropicNormalizedTerm(t1, halfDir, anisoData.anisoPower)*anisoData.anisoGlass ;

  
    half3 specularTerm = D ;
     
  
  #else

    #ifdef NOT_GGX
        half specularTerm = 0.0;
           
    #else

         
            
            float NoH = saturate(dot(float3(normalWS), halfDir));


            half specularTerm;
     
            #ifdef CUSTOM_GGX


            if(_CustomGGX)
            {
     
                float a = ( NoH*NoH * (brdfData.roughness2 - 1) + 1 );
                float D = brdfData.roughness2 *_SpecPower / (a*a);
                specularTerm =  clamp(D, 0.0, 1000.0);
                return specularTerm;
            }

            #endif

            half LoH = half(saturate(dot(lightDirectionWS, halfDir)));

            // GGX Distribution multiplied by combined approximation of Visibility and Fresnel
            // BRDFspec = (D * V * F) / 4.0
            // D = roughness^2 / ( NoH^2 * (roughness^2 - 1) + 1 )^2
            // V * F = 1.0 / ( LoH^2 * (roughness + 0.5) )
            // See "Optimizing PBR for Mobile" from Siggraph 2015 moving mobile graphics course
            // https://community.arm.com/events/1155

            // Final BRDFspec = roughness^2 / ( NoH^2 * (roughness^2 - 1) + 1 )^2 * (LoH^2 * (roughness + 0.5) * 4.0)
            // We further optimize a few light invariant terms
            // brdfData.normalizationTerm = (roughness + 0.5) * 4.0 rewritten as roughness * 4.0 + 2.0 to a fit a MAD.
            float d = NoH * NoH * brdfData.roughness2MinusOne + 1.00001f;

            half LoH2 = LoH * LoH;
            

            
         
            specularTerm = brdfData.roughness2 / ((d * d) * max(0.1h, LoH2) * brdfData.normalizationTerm);
         
              
            // On platforms where half actually means something, the denominator has a risk of overflow
            // clamp below was added specifically to "fix" that, but dx compiler (we convert bytecode to metal/gles)
            // sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...))
            
 

            #if REAL_IS_HALF
                specularTerm = specularTerm - HALF_MIN;
                // Update: Conservative bump from 100.0 to 1000.0 to better match the full float specular look.
                // Roughly 65504.0 / 32*2 == 1023.5,
                // or HALF_MAX / ((mobile) MAX_VISIBLE_LIGHTS * 2),
                // to reserve half of the per light range for specular and half for diffuse + indirect + emissive.
                specularTerm = clamp(specularTerm, 0.0, 1000.0); // Prevent FP16 overflow on mobiles
            #endif
         
    #endif

    #endif
     
    return specularTerm;
}

half3 LchLightingPhysicallyBasedBackLight(BRDFData brdfData, 
    LchAnisoData anisoData,
    half3 lightColor, half3 lightDirectionWS, half lightAttenuation,
    half3 normalWS, half3 viewDirectionWS ,half backLight)
{



    
    half baseNdotL = dot(normalWS, lightDirectionWS);

  

   
    half3 radiance ;


    
    half NdotL = max(baseNdotL,0);
    radiance = lightColor * (lightAttenuation * NdotL);
    
    

 
    half3 brdf ;


    if(baseNdotL<0)
    {
    
        brdf = 0;
        lightDirectionWS =-lightDirectionWS;

        half3 sp =  LchDirectBRDFSpecular(brdfData, anisoData,normalWS,
        anisoData.anisoDirWS,
        lightDirectionWS, viewDirectionWS);
           
        #if defined(ANISOTROPIC_ON) || defined(ANISOTROPIC_FLOWMAP) 
            brdf =  (brdfData.albedo +1)* sp ; 
        #else
            brdf = brdfData.specular * sp *backLight; 
        #endif
        return brdf*lightColor * -baseNdotL;
  
        
    }
    else
    {
        brdf = brdfData.diffuse ; 
        half3 sp =  LchDirectBRDFSpecular(brdfData, anisoData,normalWS,
        anisoData.anisoDirWS,
        lightDirectionWS, viewDirectionWS);
        #if defined(ANISOTROPIC_ON) || defined(ANISOTROPIC_FLOWMAP) 
         brdf +=  (brdfData.albedo +1)* sp ; 
        #else
         brdf += brdfData.specular * sp   ; 
        #endif
        brdf *= radiance;
    }

    
    
   
    return brdf ;
   
    
     
}
#ifdef HALF_LAMBERT
half3 LchLightingPhysicallyBased(BRDFData brdfData, 
    LchAnisoData anisoData,
    half3 lightColor, half3 lightDirectionWS, half lightAttenuation,
    half3 normalWS, half3 viewDirectionWS )
{

    
    half baseNdotL = dot(normalWS, lightDirectionWS) ;
     half NdotL = max(0,baseNdotL);


     half3 radiance = lightColor * (lightAttenuation * NdotL);
     half lightAttenuation1 = lerp(lightAttenuation,0.5, smoothstep(0.05,0,baseNdotL)) ;
     
     half3 radiance1 = lightColor * (lightAttenuation1 * baseNdotL*0.5+0.5);
     
     radiance = lerp(radiance,radiance1,_BackLight);
 
   
 
    half3 brdf = brdfData.diffuse; 


    half3 sp =  LchDirectBRDFSpecular(brdfData, anisoData,normalWS,
    anisoData.anisoDirWS,
    lightDirectionWS, viewDirectionWS);
    #if defined(ANISOTROPIC_ON) || defined(ANISOTROPIC_FLOWMAP) 
     brdf +=  (brdfData.albedo +1)* sp ; 
    #else
     brdf += brdfData.specular * sp; 
    #endif
    
   
    return brdf * radiance;
}

#else

half3 LchLightingPhysicallyBased(BRDFData brdfData, 
    LchAnisoData anisoData,
    half3 lightColor, half3 lightDirectionWS, half lightAttenuation,
    half3 normalWS, half3 viewDirectionWS )
{

    
    half baseNdotL = dot(normalWS, lightDirectionWS);

    #ifdef HALF_LAMBERT
          
        half NdotL = max(0,baseNdotL);
        half3 radiance = lightColor * (lightAttenuation * NdotL);
         radiance += lightColor*0.3*(1.0-max(0,-baseNdotL));
    #else
        half NdotL = max(baseNdotL,0);
        half3 radiance = lightColor * (lightAttenuation * NdotL);
    #endif
    

    //Half Lambert 
   
 
    half3 brdf = brdfData.diffuse; 


    half3 sp =  LchDirectBRDFSpecular(brdfData, anisoData,normalWS,
    anisoData.anisoDirWS,
    lightDirectionWS, viewDirectionWS);

 
    #if defined(ANISOTROPIC_ON) || defined(ANISOTROPIC_FLOWMAP) 
     brdf +=  (brdfData.albedo +1)* sp ; 
    #else
     brdf += brdfData.specular * sp  ; 
      
    #endif
    
   
    return brdf * radiance;
}


 
#endif



#endif